//PEERREVIEW: no PTT header!

#include <stdio.h>							// USES
#include <errno.h>							// USES
#include <fcntl.h>							// USES
#include <stdlib.h>							// USES
#include <unistd.h>							// USES
#include <sys/ioctl.h>						// USES
#include <sys/socket.h>						// USES
#include <bluetooth/bluetooth.h>			// USES
#include <bluetooth/bluetooth.h>			// USES
#include <bluetooth/sdp.h>					// USES
#include <bluetooth/sco.h>					// USES
#include <bluetooth/sdp_lib.h>				// USES
#include <bluetooth/rfcomm.h>				// USES
#include <bluetooth/l2cap.h>				// USES
#include <glib.h>							// USES

// --------------------------------------------------
// This code is adaptaion from http://www.btessentials.com/examples/bluez/sdp-register.c
// --------------------------------------------------

const char*		INPUT_STREAM			= "/tmp/.BT_CLOUD_ACTIVE_CONNECTION_IN";
const char*		OUTPUT_STREAM			= "/tmp/.BT_CLOUD_ACTIVE_CONNECTION_OUT";
const char*		ACTIVE_CONNECTION_FLAG	= "/tmp/.pc_comm_active_bt_connection";

#define UUID_LENGTH 256
#define MAX_DATA_PORTION 100024

///////////////////////////////////////////////////////////////
/*!
//\par		Description:
//			This method is used to register SDP session on specified \b rfcomm_channel
//
//\par		Parameters:
//\arg		[IN] \b rfcomm_channel - RFCOMM channel used to register SDP session
//
//\par		Return value:
//			sdp_session_t	- pointer to registered session
//
*/
sdp_session_t* register_service(uint8_t rfcomm_channel)
{
	uint32_t			svc_uuid_int[]		= {   0x01110000, 0x00100000, 0x80000080, 0xE6BD0D41 };
    const char*			service_name		= "Pruftechnik PCCommunication";
    const char*			svc_dsc				= "Pruftechnik PCCommunication protocol";
    const char*			service_prov		= "Pruftechnik";
    uuid_t				root_uuid;
	uuid_t				l2cap_uuid;
	uuid_t				rfcomm_uuid;
	uuid_t				svc_uuid;
	uuid_t				svc_class_uuid;
    sdp_list_t*			l2cap_list			= 0;
    sdp_list_t*			rfcomm_list			= 0;
    sdp_list_t*			root_list			= 0;
    sdp_list_t*			proto_list			= 0;
    sdp_list_t*			access_proto_list	= 0;
    sdp_list_t*			svc_class_list		= 0;
    sdp_list_t*			profile_list		= 0;
    sdp_data_t*			channel				= 0;
    sdp_profile_desc_t	profile;
    sdp_record_t		record				= { 0 };
    sdp_session_t*		session				= 0;

    // set the general service ID
    sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
    sdp_set_service_id( &record, svc_uuid );

    char str[UUID_LENGTH] = "";
    sdp_uuid2strn(&svc_uuid, str, UUID_LENGTH);
    //printf("Registering UUID %s\n", str);

    // set the service class
    sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID);
    svc_class_list = sdp_list_append(0, &svc_class_uuid);
    sdp_set_service_classes(&record, svc_class_list);

    // set the Bluetooth profile information
    sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
    profile.version = 0x0100;
    profile_list = sdp_list_append(0, &profile);
    sdp_set_profile_descs(&record, profile_list);

    // make the service record publicly browsable
    sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
    root_list = sdp_list_append(0, &root_uuid);
    sdp_set_browse_groups( &record, root_list );

    // set l2cap information
    sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
    l2cap_list = sdp_list_append( 0, &l2cap_uuid );
    proto_list = sdp_list_append( 0, l2cap_list );

    // register the RFCOMM channel for RFCOMM sockets
    sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
    channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
    rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
    sdp_list_append( rfcomm_list, channel );
    sdp_list_append( proto_list, rfcomm_list );

    access_proto_list = sdp_list_append( 0, proto_list );
    sdp_set_access_protos( &record, access_proto_list );

    // set the name, provider, and description
    sdp_set_info_attr(&record, service_name, service_prov, svc_dsc);

    // connect to the local SDP server, register the service record,
    // and disconnect
    session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
    sdp_record_register(session, &record, 0);

    // cleanup
    sdp_data_free( channel );
    sdp_list_free( l2cap_list, 0 );
    sdp_list_free( rfcomm_list, 0 );
    sdp_list_free( root_list, 0 );
    sdp_list_free( access_proto_list, 0 );
    sdp_list_free( svc_class_list, 0 );
    sdp_list_free( profile_list, 0 );

    return session;
}

///////////////////////////////////////////////////////////////
/*!
//\par		Description:
//			Main routiune that start SDP session and allows other devices to discover it and connet.
//
//\par		Parameters:
//			None
//
//\par		Return value:
//			None
//
*/
int main(int argc, char **argv)
{
    int				port		= 3;
    sdp_session_t*	session		= register_service(port);

    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
    char			buf[MAX_DATA_PORTION] = { 0 };

    int s, client, bytes_read;
    socklen_t opt = sizeof(rem_addr);
    // allocate socket
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

    // bind socket to port 1 of the first available
    // local bluetooth adapter
    loc_addr.rc_family = AF_BLUETOOTH;
    loc_addr.rc_bdaddr = *BDADDR_ANY;
    loc_addr.rc_channel = (uint8_t) port;
    int r;
    r = bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));

	// put socket into listening mode
    r = listen(s, 1);

	remove( ACTIVE_CONNECTION_FLAG );
	mkfifo( INPUT_STREAM, 0666 );
	mkfifo( OUTPUT_STREAM, 0666 );
	
	while ( 1 )
	{
		fd_set SFileToWatch;

		FD_ZERO( &SFileToWatch );

		struct timeval SDelay;

		SDelay.tv_usec = 0;
		SDelay.tv_sec = 20;
		
		// accept one connection
		client = accept(s, (struct sockaddr *)&rem_addr, &opt);
		
		int iConnectionFlagFile		= open ( ACTIVE_CONNECTION_FLAG, O_RDWR|O_CREAT);
		
		if ( iConnectionFlagFile >= 0 )
		{
			close( iConnectionFlagFile );
		}
		
		int fd_out = open(OUTPUT_STREAM, O_WRONLY);
		int fd_in = open(INPUT_STREAM, O_RDONLY);
		
		if ( fd_out >=0 && fd_in >= 0 )
		{
			memset( buf, 0, sizeof( buf ) );

			// read data from the client
			bytes_read = read(client, buf, sizeof(buf));
			while ( bytes_read > 0 )
			{
				write( fd_out, buf, bytes_read );

				// send back data
				memset( buf, 0, sizeof( buf ) );
				
				FD_SET( fd_in, &SFileToWatch );

				if ( select( fd_in+1, &SFileToWatch, 0, 0, &SDelay ) > 0 )
				{
					bytes_read = read( fd_in, buf, sizeof( buf) );
					if ( bytes_read > 0 )
					{
						write( client, buf, bytes_read );
					}
				}
				
				bytes_read = read( client, buf, sizeof(buf) );
			}
		}
		remove( ACTIVE_CONNECTION_FLAG );
		close( fd_out );
		close ( fd_in );
		
		// close connection
		close(client);
	}
    close(s);
    sdp_close( session );

    return 0;
}
